package org.openfdtd.core3d;

import org.openfdtd.core3d.Util;
import com.sun.j3d.utils.picking.PickCanvas;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.util.ArrayList;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.Shape3D;
import javax.vecmath.Color3f;

/**
 *
 * @author Dórian C. Langbeck
 */
public class EditableUniverse extends BasicUniverse {
    public static final int SELECT_OBJECT       = 0;
    public static final int SELECT_SURFACE      = 2;
    
    public static final int SINGLE_SELECTION    = 1;
    public static final int MULTI_SELECTION     = 3;

    //Listenners
    private ArrayList<SurfaceListenner> surfaceListenner;
    private ArrayList<ObjectListenner> objectListenner;

    protected EditableObject3D focusObject;
    protected EditableObject3D activeObj;
    protected boolean singleSelection;
    protected Surface focusSurface;
    protected PickCanvas pCanvas;
    protected Shape3D overShape;
    protected int selectMode;
    
    public EditableUniverse(Canvas3D canvas) {
        super(canvas);
    }

    public EditableUniverse(Canvas3D canvas, Color3f bgColor) {
        super(canvas, bgColor);

        pCanvas = new PickCanvas(canvas, objRoot);
        pCanvas.setMode(PickCanvas.GEOMETRY);

        selectMode = SELECT_OBJECT;
        singleSelection = true;
        
        objectListenner = new ArrayList<ObjectListenner>();
        surfaceListenner = new ArrayList<SurfaceListenner>();
        
        configureListenners();
    }

    public boolean isSingleSelection() {
        return singleSelection;
    }

    public void setSingleSelection(boolean singleSelection) {
        this.singleSelection = singleSelection;
    }

    public void setSelectionMode(int mode) throws UnsupportedOperationException {
        if (mode != SELECT_OBJECT || mode != SELECT_SURFACE)
            throw new UnsupportedOperationException();

        selectMode = mode;
    }

    public int getSelectionMode() {
        return selectMode;
    }
    
    public Surface getSurfaceFocusOwner() {
        return focusSurface;
    }
    
    public EditableObject3D getObjectFocusOwner() {
        return focusObject;
    }

    /**
     * Redireciona, refinadamente, os eventos ocorridos no canvas para
     * os listenners cadastrados.
     */
    private void configureListenners() {
        Canvas3D canvas = pCanvas.getCanvas();

        canvas.addMouseMotionListener(new MouseMotionAdapter() {
            @Override
            public void mouseMoved(MouseEvent e) {
                Surface face = Util.pickSurface(pCanvas, e);
                if (face == null) {
                    focusSurface = null;
                    focusObject = null;
                    return;
                }

                if (face == focusSurface)
                    return;
                
                EditableObject3D obj = Util.getObject3D(face);
                for (SurfaceListenner sl : surfaceListenner)
                    sl.mouseEntered(face, obj, e);

                if (obj != focusObject)
                    for (ObjectListenner ol : objectListenner)
                        ol.mouseEntered(obj, e);


                focusObject = obj;
                if (focusSurface == null) {
                    obj = Util.getObject3D(focusSurface);
                    for (SurfaceListenner sl : surfaceListenner)
                        sl.mouseExited(focusSurface, obj, e);

                    if (obj != focusObject)
                        for (ObjectListenner ol : objectListenner)
                            ol.mouseExited(obj, e);
                }

                focusSurface = face;
            }
        });
        
        canvas.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                Surface face = Util.pickSurface(pCanvas, e);
                EditableObject3D obj = Util.getObject3D(face);

                for (SurfaceListenner sl : surfaceListenner)
                    sl.mouseClicked(face, obj, e);

                for (ObjectListenner ol : objectListenner)
                    ol.mouseClicked(obj, e);
            }

            @Override
            public void mousePressed(MouseEvent e) {
                Surface face = Util.pickSurface(pCanvas, e);
                EditableObject3D obj = Util.getObject3D(face);

                for (SurfaceListenner sl : surfaceListenner)
                    sl.mousePressed(face, obj, e);

                for (ObjectListenner ol : objectListenner)
                    ol.mousePressed(obj, e);
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                Surface face = Util.pickSurface(pCanvas, e);
                EditableObject3D obj = Util.getObject3D(face);

                for (SurfaceListenner sl : surfaceListenner)
                    sl.mouseReleased(face, obj, e);

                for (ObjectListenner ol : objectListenner)
                    ol.mouseReleased(obj, e);
            }
        });
    }

    public void addSurfaceListenner(SurfaceListenner l) {
        if (l == null)
            return;

        surfaceListenner.add(l);
    }

    public void addObjectListenner(ObjectListenner l) {
        if (l == null)
            return;

        objectListenner.add(l);
    }

    public void setActiveObject(EditableObject3D obj) {
        if (activeObj != null)
            activeObj.setEditable(false);
        
        activeObj = obj;
        activeObj.setEditable(true);
    }
}
